以下是流程簡單的描述
IL_000a: callvirt instance class [System.Net.Http]System.Threading.Tasks.Task`1<string>
[System.Net.Http]System.Net.Http.HttpClient::GetStringAsync(string)
IL_000f: callvirt instance valuetype [System.Runtime]System.Runtime.CompilerServices.TaskAwaiter`1<string>
class [System.Runtime]System.Threading.Tasks.Task`1<string>::GetAwaiter()
IL_0014: stloc.0 // 暫存 awaiter
IL_0015: ldloca.s 0
IL_0017: call instance bool [System.Runtime]System.Runtime.CompilerServices.TaskAwaiter`1<string>::get_IsCompleted()
IL_001c: brtrue.s IL_0039
// 未完成路徑(掛起)
IL_001e: ldarg.0
IL_001f: ldc.i4.0
IL_0020: stfld int32 <>1__state
IL_0025: ldarg.0
IL_0026: ldloc.0
IL_0027: stfld valuetype TaskAwaiter`1<string> <>u__1
IL_002c: ldarg.0
IL_002d: ldflda valuetype AsyncTaskMethodBuilder`1<int32> <>t__builder
IL_0032: ldloca.s 0
IL_0034: ldarg.0
IL_0035: call instance void AsyncTaskMethodBuilder`1<int32>::AwaitUnsafeOnCompleted(
!!0&, !!1&)
IL_003a: ret
// 已完成快速路徑
IL_0039: ldloca.s 0
IL_003b: call instance string TaskAwaiter`1<string>::GetResult()
可被 await 的型別需提供:
TaskAwaiter / ValueTaskAwaiter 為內建。AwaitUnsafeOnCompleted 優先使用 UnsafeOnCompleted 以避免不必要的 ExecutionContext 複製。
IsCompleted 為 true 時直接續執行,不掛起也不排程。大量同步命中(快取、已完成 I/O)是使用 ValueTask 降低配置的前提。
影響續接排程:
Q. ValueTask 差異
AsyncValueTaskMethodBuilder:
Q. 為何可能出現盒裝狀態機
ref struct 無法實作介面,當需以 IAsyncStateMachine 形式傳遞(如偵錯掛勾)可能產生一次性 boxing,編譯器已盡量避免。